#include "ShReflectProcess.h"
#include "Utils/LogUtil.h"
#include "Render/RenderState.h"
#include "Core/CoreGlobals.h"
#include "Game/Scene/Entity.h"
#include "Game/Component/Model.h"
#include "Render/Buffer/VertexBuffer.h"
#include "Render/Buffer/IndexBuffer.h"
#include "Render/Buffer/CustomBuffer.h"
#include "LocalShader.h"

void ShReflectProcess::OnInit()
{
	mShEntity = static_cast<LocalEntity*>(mGameScene->GetEntityByName("shSphere"));

	Ubo ubo;
	ubo.proj = mGameScene->GetCamera().GetProj();
	ubo.view = mGameScene->GetCamera().GetView();
	ubo.model = mShEntity->GetTransform().GetWorldMatrix();
	ubo.invView = glm::inverse(ubo.view);
	ubo.lodBias = 0.f;

	ENQUEUE_RENDER_COMMAND(BuildModel)([this, ubo](VkCommandBuffer commandBuffer)
		{
			Ubo entityUbo = ubo;

			Model& modelData = mShEntity->GetComponent<Model>();

			std::vector<VertexPosNormal> tempVertexs;
			tempVertexs.resize(modelData.mVertexs.size());
			for (uint32 i = 0; i < modelData.mVertexs.size(); ++i)
			{
				tempVertexs[i].pos = modelData.mVertexs[i].Position;
				tempVertexs[i].normal = modelData.mVertexs[i].Normal;
			}

			mShEntity->mVertexBuffer = VertexBuffer::Builder()
				.SetData(tempVertexs.data())
				.SetSize(tempVertexs.size() * sizeof(VertexPosNormal))
				.Build();

			mShEntity->mIndexBuffer = IndexBuffer::Builder()
				.SetData(modelData.mIndices.data())
				.SetSize(modelData.mIndices.size() * sizeof(uint32))
				.SetIndexCount(modelData.mIndices.size())
				.Build();

			mShEntity->mUboBuffer = CustomBuffer::Builder()
				.SetData(&entityUbo)
				.SetSize(sizeof(Ubo))
				.SetMemoryProperty(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
				.Build();

			mDescriptor = RHIDescriptor::Builder()
				.PushShader<ShReflectVertexShader>()
				.PushShader<ShReflectFragmentShader>()
				.SetDescriptorCount(0, 1)
				.Build();

			RefCountPtr<RHITexture> shImage = GetTexture("SphericalHarmonicsProcess", "shImage");
			RefCountPtr<RHISampler> shSampler = RHISampler::Builder()
				.SetMipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR)
				.Build();
			

			mDescriptor->SetValue("ubo", mShEntity->mUboBuffer);
			mDescriptor->SetValue("shImage", shImage, shSampler);

			mShEntity->mDescriptorMask = mDescriptor->AllocateDescriptor();

			RefCountPtr<ColorRenderTarget> colorRenderTarget = GetTexture("SkyboxProcess", "ColorRenderTarget");
			RefCountPtr<DepthRenderTarget> depthRenderTarget = GetTexture("SkyboxProcess", "DepthRenderTarget");
			RefCountPtr<RHIRenderPass> renderPass = GetRenderPass("SkyboxProcess", "RenderPass");

			mPipeline = GraphicsPipeline::Builder()
				.SetDescriptor(mDescriptor)
				.AddColorRenderTarget(colorRenderTarget)
				.SetDepthRenderTarget(depthRenderTarget)
				.SetDstStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
				.SetDstAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
				.SetSrcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
				.SetSrcAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
				.SetRenderPass(renderPass->GetRenderPass())
				.Build();
		});
}

void ShReflectProcess::OnTick(float deltaTime)
{
	Ubo ubo;
	ubo.proj = mGameScene->GetCamera().GetProj();
	ubo.view = mGameScene->GetCamera().GetView();
	ubo.model = mShEntity->GetTransform().GetWorldMatrix();
	ubo.invView = glm::inverse(ubo.view);
	ubo.lodBias = 0.f;

	ENQUEUE_RENDER_COMMAND(RecordCommand)([this, ubo](VkCommandBuffer commandBuffer)
		{
			Ubo entityUbo = ubo;

			mShEntity->mUboBuffer->WriteMemory(&entityUbo);

			vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline->GetPipeline());

			vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline->GetPipelineLayout(), 0, 1, &mShEntity->mDescriptorMask.GetDescriptorSet(), 0, nullptr);

			VkBuffer vertexBuffer = mShEntity->mVertexBuffer->GetBuffer();
			VkDeviceSize offsets = 0;
			vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, &offsets);

			VkBuffer indexBuffer = mShEntity->mIndexBuffer->GetBuffer();
			vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT32);

			vkCmdDrawIndexed(commandBuffer, mShEntity->mIndexBuffer->GetIndexCount(), 1, 0, 0, 0);

			vkCmdEndRenderPass(commandBuffer);
		});
}

void ShReflectProcess::OnResize()
{
}
